#include "credits.h"
#include "context.h"
#include <vector>
#include <sstream>
#include "course.h"

Credits::Credits(const double& credits) :
    credits_(credits)
{
}

/// Evaluates whether the requirement of minimum number of credits is fulfilled
/// within the given context.
/// \param context The context within which the requirement is tested.
/// \return True if the number of credits the student in the given context has
/// accumulated is equal to or greater than this requirement's minimum credits
/// value.  False otherwise.
bool Credits::evaluate(Context& context)
{
    // check for credits requirement
    Student student = context.student();
    std::vector< boost::shared_ptr<Course> > completed_courses = student.getCompletedCourses();
    // TODO:  find a way to get credits completed in O(1), because this function
    //        will be called many times.
    double credits_completed = 0;
    for( std::vector< boost::shared_ptr<Course> >::const_iterator i = completed_courses.begin();
         i != completed_courses.end(); ++i ) {
        credits_completed += (*i)->getCredits();
    }
    return credits_completed >= credits_;
}

/// Generates a string representation of the credits requirement.
/// \param context Merely fulfills the interface signature of the function.
/// Not used.
/// \return The string representation of the credits requirement.
std::string Credits::to_string(Context&)
{
    std::ostringstream oss;
    oss << credits_ << " credits";
    return oss.str();
}

/// Returns 1 as the count of requirements this credits requirement presents.
/// \param context Merely fulfills the interface signature of the function.
/// Not used.
/// \return The number of requirements this credits requirement presents, which
/// is always 1.
std::size_t Credits::count(Context&)
{
    return 1;
}

/// A dummy definition to complete implementation of courses extraction.
/// \return An empty list.
std::list<Course> Credits::courses()
{
    return std::list<Course>();
}
